package com.zytech.zspider.core;

import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zytech.modules.lang.Requires;
import com.zytech.modules.lang.annotations.Immutable;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author siuming
 */
@Immutable
public class TaskGenDefinition implements Serializable {
    private static final long serialVersionUID = 4344897148182545782L;

    private final String name;
    private final String generateExpr;

    private final String startExpr;
    private final String finishExpr;
    private final Map<String, String> collectExprs;
    private final List<TaskGenDefinition> nexts;
    private final TaskResultPipelineSettings pipelineSettings;

    TaskGenDefinition(Builder builder) {
        Requires.hasText(builder.name, "name must not be null or empty.");
        Requires.hasText(builder.generateExpr, "generateExpr must not be null or empty");
        this.name = builder.name;
        this.generateExpr = builder.generateExpr;
        this.nexts = builder.nexts;
        this.startExpr = builder.startExpr;
        this.finishExpr = builder.finishExpr;
        this.pipelineSettings = builder.pipelineSettings;
        this.collectExprs = builder.collectExprs;
    }

    /**
     * @return
     */
    public String getName() {
        return name;
    }

    /**
     * @return
     */
    public String getGenerateExpr() {
        return generateExpr;
    }

    /**
     * 2     * @return
     */
    public boolean isEmptyNexts() {
        return nexts.isEmpty();
    }

    /**
     * @return
     */
    public List<TaskGenDefinition> getNexts() {
        return ImmutableList.copyOf(nexts);
    }

    /**
     * @return
     */
    public String getStartExpr() {
        return startExpr;
    }

    /**
     * @return
     */
    public String getFinishExpr() {
        return finishExpr;
    }

    /**
     * @return
     */
    public Map<String, String> getCollectExprs() {
        return Collections.unmodifiableMap(collectExprs);
    }

    /**
     * @return
     */
    public TaskResultPipelineSettings getPipelineSettings() {
        return pipelineSettings;
    }

    @Override
    public String toString() {
        return Objects
                .toStringHelper(this)
                .add("name", getName())
                .add("generateExpr", getGenerateExpr())
                .add("startExpr", getStartExpr())
                .add("finishExpr", getFinishExpr())
                .add("resultHanlder", getPipelineSettings())
                .add("nexts", getNexts())
                .toString();
    }

    /**
     * @return
     */
    public static Builder ofBuilder() {
        return new Builder();
    }

    public static class Builder {
        String name;
        String startExpr;
        String finishExpr;
        String generateExpr;
        Map<String, String> collectExprs = Maps.newHashMap();

        TaskResultPipelineSettings pipelineSettings;
        List<TaskGenDefinition> nexts = Lists.newArrayList();

        Builder() {
        }

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder onStart(String startScript) {
            this.startExpr = startScript;
            return this;
        }

        public Builder onResult(TaskResultPipelineSettings pipelineSettings) {
            this.pipelineSettings = pipelineSettings;
            return this;
        }

        public Builder onFinish(String finishScript) {
            this.finishExpr = finishScript;
            return this;
        }

        public Builder onCollects(Map<String, String> collectScripts) {
            Requires.notNull(collectScripts, "collectScripts must not be null.");
            this.collectExprs = collectScripts;
            return this;
        }

        public Builder onGenerate(String generateScript) {
            this.generateExpr = generateScript;
            return this;
        }

        public Builder next(TaskGenDefinition next) {
            Requires.notNull(next, "next must not be null.");
            this.nexts.add(next);
            return this;
        }

        public Builder nexts(List<TaskGenDefinition> nexts) {
            Requires.notNull(nexts, "nexts must not be null.");
            for (TaskGenDefinition next : nexts) {
                next(next);
            }
            return this;
        }

        public TaskGenDefinition build() {
            return new TaskGenDefinition(this);
        }
    }
}
